;;    Copyright ? 2013 Jinson Xu, Gu Zhan, Elizabeth Tang, He Tao
;;    Contact: jinson.xu@nus.edu.sg, samisitspecialist@gmail.com, 
;;             eliz.thf@gmail.com, hetao123@gmail.com

;;    This file is part of Electives-Xpert.
;;    Template and rule definitions are declared here.
;;
;;    Electives-Xpert is free software: you can redistribute it and/or modify
;;    it under the terms of the GNU General Public License as published by
;;    the Free Software Foundation, either version 3 of the License, or
;;    (at your option) any later version.

;;    Electives-Xpert is distributed in the hope that it will be useful,
;;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;    GNU General Public License for more details.

;;    You should have received a copy of the GNU General Public License
;;    along with Electives-Xpert.  If not, see <http://www.gnu.org/licenses/>.

(defmodule MAIN (export ?ALL))
   
;; Template Definitions
    
(deftemplate currentElective
    (slot code ;;elective code
        (type SYMBOL)
        (default ?DERIVE))    
    (slot elective ;;name of current elective
        (type STRING)
        (default ?DERIVE)) 
    (slot category ;;category of current elective
        (type STRING)
        (default ?DERIVE))
    (slot cf ;;cf value
        (type NUMBER)
        (default 0.5))
    (slot cf_career_plans_technical ;;tech inclination data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_career_plans_management ;;management inclination data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_requirements_design_construction ;;interests requirements data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_software_development_platforms_technologies ;;interest software dev data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_it_infrastructure_technology ;;interests IT infra data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_advanced_it_management ;;interests advanced IT mgmt data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_technopreneurship_innovation ;;interests technopreneurship data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_interests_knowledge_engineering_techniques ;;interests knowledge engineering data CF
        (type NUMBER)
        (default 0.5)
    )  
    (slot cf_jobscope_developer ;;jobscope developer data CF
        (type NUMBER)
        (default 0.5)
    )
    (slot cf_jobscope_analyst ;; jobscope analyst data CF
        (type NUMBER)
        (default 0.5)
    )   
    (slot cf_jobscope_architect ;;jobscope architect data CF
        (type NUMBER)
        (default 0.5)
    )   
    (slot cf_jobscope_pm_pmo ;;jobscope pm/pmo data CF
        (type NUMBER)
        (default 0.5)
    )   
    (slot cf_jobscope_it_manager ;;jobscope IT manager data CF
        (type NUMBER)
        (default 0.5)
    )   
    (slot cf_jobscope_network_security ;;jobscope network security data CF
        (type NUMBER)
        (default 0.5)
    )   
    (slot cf_jobscope_others ;;jobscope others data CF
        (type NUMBER)
        (default 0.5)
    )                                                 
)


(deftemplate currentGoal 
    (slot goal ;;name of current goal
        (type STRING)
        (default ?DERIVE)) 
    (slot cf
        (type FLOAT)
        (default 0.5))
)


(deftemplate workingGoal 
    (slot goal ;;name of working goal
        (type STRING)
        (default ?DERIVE)) 
    (slot cf
        (type FLOAT)
        (default 0.5))
)


;; EOF Template Definitions




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Global Variables

(defglobal
    ?*developer-cf* = 0.0
    ?*analyst-cf* = 0.0
    ?*architect-cf* = 0.0
    ?*pm-cf* = 0.0
    ?*it-manager-cf* = 0.0
    ?*network-security-cf* = 0.0
    ?*others-cf* = 0.0
    ?*interests_reqsdesign-cf* = 0.0
    ?*interests_softwaredev-cf* = 0.0
    ?*interests_infratech-cf* = 0.0
    ?*interests_advanceditmgmt-cf* = 0.0
    ?*interests_technoinno-cf* = 0.0
    ?*interests_ke-cf* = 0.0
    ?*recommendation_raw_string* = ""
    ?*recommendation_string* = "")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Rule Definitions


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; CF combination for multiple conclusions RULES
;;; treat this as a black-box
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;combine POSITIVE certainty factors for multiple conclusions
;cf(cf1,cf2) = cf1 + cf2 * (1- cf1)

(defrule combine-positive-cf
  ?f1 <- (currentGoal (goal ?g)(cf ?cf1&:(>= ?cf1 0)))
  ?f2 <- (workingGoal (goal ?g)(cf ?cf2&:(>= ?cf2 0)))
  (test (neq ?f1 ?f2)) ; test pointers and not value
  =>
  (retract ?f2)
  (modify ?f1 (cf =(+ ?cf1 (* ?cf2 (- 1 ?cf1)))))
)

;combine NEGATIVE cf
;cf(cf1,cf2) = cf1 + cf2 * (1 + cf1)

(defrule combine-neg-cf
 (declare (salience -1))
  ?f1 <- (currentGoal   (goal ?g)(cf ?cf1&:(<= ?cf1 0)))
  ?f2 <- (workingGoal (goal ?g)(cf ?cf2&:(<= ?cf2 0)))
  (test (neq ?f1 ?f2))
  =>
  (retract ?f2)
  (modify ?f1 (cf =(+ ?cf1 (* ?cf2 (+ 1 ?cf1)))))
)

;combine one POSITIVE and one NEGATIVE
;cf(cf1,cf2) = (cf1 + cf2) / 1 - MIN[abs(cf1),abs(cf2)]

(defrule neg-pos-cf
 (declare (salience -1))
  ?f1 <- (currentGoal (goal ?g) (cf ?cf1))
  ?f2 <- (workingGoal (goal ?g) (cf ?cf2))
  (test (neq ?f1 ?f2))
  (test (< (* ?cf1 ?cf2) 0))
  =>
  (retract ?f2)
  (modify ?f1 (cf =(/ (+ ?cf1 ?cf2) (- 1 (min (abs ?cf1) (abs ?cf2))))))
)



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; BUSINESS RULES
;;; note that stage1 and stage2 are combined into one assert statement within the defrule
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;**** Rule 1: Ask student for track type
;**** this will increase the CF of your preferred elective


;*** Rule 1a: Update CF of non-KE modules
(defrule current_track_update_ke
    (student-track ?track)
    (student_least_favourite_ke ?least_favourite_ke)
    (currentElective (elective ?name) (category "Knowledge Engineering Techniques") (cf ?cf))
=>
    (if (eq ?track ke) then
        ;(printout t crlf "Current track is: " ?track ". Giving KE modules priority now...")
        (if (neq ?name ?least_favourite_ke) then 
            (assert (workingGoal (goal ?name) (cf (* ?cf 1.8))))
        )
    )
)

;**** Rule 3a: Update all workingGoals with career_goal tech inclination data CF modifications
(defrule update_with_tech_inclination
    (student-track ?track)
    (course-purpose-career-rating ?career_rating)
    (career-goal-tech-inclination ?career_tech_inclination)
    (currentElective (elective ?name) (cf_career_plans_technical ?cf_cp_tech)) ; get the RULE CF for "IF TECH INCLINED (data CF) then XX elective (will be able to help you in your career goal)     
=>
    (assert (workingGoal (goal ?name) (cf (* (min ?career_rating ?career_tech_inclination) ?cf_cp_tech))))
)



;**** Rule 3b: Update all workingGoals with career_goal management inclination data CF modifications
(defrule update_with_management_inclination
    (student-track ?track)
    (course-purpose-career-rating ?career_rating)
    (career-goal-management-inclination ?career_man_inclination)
    (currentElective (elective ?name) (cf_career_plans_management ?cf_cp_man)) ; get the RULE CF for "IF MANAGEMENT INCLINED (data CF) then XX elective (will be able to help you in your career goal)"      
=>
    (assert (workingGoal (goal ?name) (cf (* (min ?career_rating ?career_man_inclination) ?cf_cp_man))))
)

;**** Rule 4a: Update job roles data CF with the ranked jobscopes that user entered.
(defrule current_job_roles_cf
    (jobroles_string ?jobroles_string)
=>
    (bind ?jobroles_array (str-explode ?jobroles_string))
        
    (loop-for-count(?cnt 1 3) do
        (bind ?jobid (nth$ ?cnt ?jobroles_array))
        (printout t crlf ?cnt ": " (nth$ ?cnt ?jobroles_array))
        
        (switch ?cnt
            (case 1 then(bind ?newcf 0.5))
            (case 2 then (bind ?newcf 0.3))
            (case 3 then (bind ?newcf 0.2))
        )
              
        (switch ?jobid
            (case 1 then (bind ?*developer-cf* ?newcf))
            (case 2 then (bind ?*analyst-cf* ?newcf))
            (case 3 then (bind ?*architect-cf* ?newcf))
            (case 4 then (bind ?*pm-cf* ?newcf))
            (case 5 then (bind ?*it-manager-cf* ?newcf))
            (case 6 then (bind ?*network-security-cf* ?newcf))
            (case 7 then (bind ?*others-cf* ?newcf))
        )        
    )
    (assert (job_roles_cf_set yes));                                       
)


;**** Rule 4a1: Update all workingGoals with all skillset CF modifications
(defrule update_with_skillsets
    (job_roles_cf_set ?jcfSet)
    (currentElective (elective ?name) (cf_jobscope_developer ?devruleCF) (cf_jobscope_analyst ?anaruleCF) (cf_jobscope_architect ?archruleCF) (cf_jobscope_pm_pmo ?pmruleCF) (cf_jobscope_it_manager ?itmruleCF) (cf_jobscope_network_security ?nsruleCF) (cf_jobscope_others ?oruleCF)) ; get the RULE CF for        
=>
    (assert (workingGoal (goal ?name) (cf (* ?*developer-cf* ?devruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*analyst-cf* ?anaruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*architect-cf* ?archruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*pm-cf* ?pmruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*it-manager-cf* ?itmruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*network-security-cf* ?nsruleCF))))
    (assert (workingGoal (goal ?name) (cf (* ?*others-cf* ?oruleCF))))        
)




;**** Rule 5: Ask student what his top 3 interest categories are 



;**** Rule 5a: Update interests data CF with the ranked interest categories that user entered.
(defrule interest_categories_cf
    (interests_string ?interests_string)
=>
    (bind ?interests_array (str-explode ?interests_string))
        
    (loop-for-count(?cnt 1 3) do
        (bind ?interestid (nth$ ?cnt ?interests_array))
        
        (switch ?cnt
            (case 1 then(bind ?newcf 0.5))
            (case 2 then (bind ?newcf 0.3))
            (case 3 then (bind ?newcf 0.2))
        )
        
        (switch ?interestid
            (case 1 then (bind ?*interests_reqsdesign-cf* ?newcf))
            (case 2 then (bind ?*interests_softwaredev-cf* ?newcf))
            (case 3 then (bind ?*interests_infratech-cf* ?newcf))
            (case 4 then (bind ?*interests_advanceditmgmt-cf* ?newcf))
            (case 5 then (bind ?*interests_technoinno-cf* ?newcf))
            (case 6 then (bind ?*interests_ke-cf* ?newcf))
        )        
    )
    (assert (interests_cf_set yes));                                       
)


;**** Rule 5a1: Update all workingGoals with interest categories CF modifications
(defrule update_with_interest_categories
    (course-purpose-interest-rating ?interest-rating) ;; level of confidence that the student's taking the course due to interest
    (interests_cf_set ?interestsCFset) ;; control fact
    (currentElective (elective ?name) (cf_interests_requirements_design_construction ?reqsruleCF) (cf_interests_software_development_platforms_technologies ?softwaredevCF) (cf_interests_it_infrastructure_technology ?itinfraCF) (cf_interests_advanced_it_management ?aitCF) (cf_interests_technopreneurship_innovation ?techinnoCF) (cf_interests_knowledge_engineering_techniques ?keCF))
=>
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_reqsdesign-cf* ?interest-rating) ?reqsruleCF)))) ;; stage 1 and 2 for interests premises to elective conclusions
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_softwaredev-cf* ?interest-rating) ?softwaredevCF)))) ;; stage 1 and 2 for interests premises to elective conclusions
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_infratech-cf* ?interest-rating) ?itinfraCF)))) ;; stage 1 and 2 for interests premises to elective conclusions
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_advanceditmgmt-cf* ?interest-rating) ?aitCF)))) ;; stage 1 and 2 for interests premises to elective conclusions
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_technoinno-cf* ?interest-rating) ?techinnoCF)))) ;; stage 1 and 2 for interests premises to elective conclusions               
    (assert (workingGoal (goal ?name) (cf (* (min ?*interests_ke-cf* ?interest-rating) ?keCF)))) ;; stage 1 and 2 for interests premises to elective conclusions       
)





;**** Rule 6: Populate raw results string
(defrule populate_raw_results_string
    (declare (salience -10))
    (currentGoal (goal ?name) (cf ?cf))
=>    
    (bind ?*recommendation_raw_string* (str-cat ?*recommendation_raw_string* " " ?name " " ?cf)) ;;for each currentGoal fact, we simply concat the name and cf into the raw results string global variable
)

; sort/integration code + Par2 code starts here...

; Bleow sort_course_list is the interface between sort/integration and part 1 functions
; for sorting Weight (1-28) based on CF
; hightest CF has highest weight (28)
(deftemplate sort_course_list 
	(slot CID (type SYMBOL) (default EMPTY)) 
	(slot NAME (type STRING) (default "EMPTY")) 
	(slot CF (type NUMBER) (default 0.5)) 
	(slot WEIGHT (type NUMBER) (default 0)) 
	(slot SID (type SYMBOL) (default S0))
)
;
;
; Bleow course_list is the interface between sort/integration and part 2 functions
; deftemplate course_list (slot CID) (slot NAME) (slot CF) (slot WEIGHT) (slot SID)
; example: (course_list KE4204 "Business Analytics" 0.5 28 S0)
;
(deftemplate course_list 
	(slot CID (type SYMBOL) (default EMPTY)) 
	(slot NAME (type STRING) (default "EMPTY")) 
	(slot CF (type NUMBER) (default 0.5)) 
	(slot WEIGHT (type NUMBER) (default 0)) 
	(slot SID (type SYMBOL) (default S0))
)

; Below session_list will be used to store the goal.
(deftemplate session_list 
	(slot CID (type SYMBOL) (default EMPTY)) 
	(slot NAME (type STRING) (default "EMPTY")) 
	(slot CF (type NUMBER) (default 0.5))
	(slot WEIGHT (type NUMBER) (default 0)) 
	(slot SID (type SYMBOL) (default S0))
)


; Below "interface_facts" should come from Part 1 function; We hard-coded here for testing purpose
;(deffacts interface_facts
;	(course_list (CID KE4204) (NAME "Business Analytics") (WEIGHT 28))
;	(course_list (CID KE5205) (NAME "Text Mining") (WEIGHT 27))
;	(course_list (CID KE5204) (NAME "Genetic Algorithms") (WEIGHT 26))
;	(course_list (CID SG5220) (NAME "Research on Advanced IT Topics I") (WEIGHT 25))
;	(course_list (CID SG5205) (NAME "Software Metrics & Process Improvement") (WEIGHT 24))
;	(course_list (CID SG4205) (NAME "Information System Security") (WEIGHT 23))
;	(course_list (CID SG4210) (NAME "Enterprise .NET I") (WEIGHT 22))
;	(course_list (CID SG5214) (NAME "Software Requirement Engineering") (WEIGHT 21))
;	(course_list (CID KE4202) (NAME "Case Based Reasoning") (WEIGHT 20))
;	(course_list (CID KE4205) (NAME "Knowledge management") (WEIGHT 19))
;	(course_list (CID SG5221) (NAME "Research on Advanced IT Topics II") (WEIGHT 18))
;	(course_list (CID SG5228) (NAME "Service Innovation") (WEIGHT 17))
;	(course_list (CID SG5219) (NAME "IT Law") (WEIGHT 16))
;	(course_list (CID SG5207) (NAME "Managing IT Outsourcing & Subcontracting") (WEIGHT 15))
;	(course_list (CID SG5211) (NAME "Business Process Management") (WEIGHT 14))
;	(course_list (CID SG5222) (NAME "IT Service management") (WEIGHT 13))
;	(course_list (CID SG5227) (NAME "Open Source for the Enterprise") (WEIGHT 12))
;	(course_list (CID SG4211) (NAME "Cloud Computing") (WEIGHT 11))
;	(course_list (CID SG5231) (NAME "Agile Software Project management") (WEIGHT 10))
;	(course_list (CID SG5226) (NAME "Enterprise .NET II") (WEIGHT 9))
;	(course_list (CID SG5209) (NAME "Enterprise Java") (WEIGHT 8))
;	(course_list (CID SG4206) (NAME "Enterprise Integration") (WEIGHT 7))
;	(course_list (CID SG4202) (NAME "Mobile Wireless Application Development") (WEIGHT 6))
;	(course_list (CID SG3204) (NAME "Human Computer Interface") (WEIGHT 5))
;	(course_list (CID SG5208) (NAME "Object Oriented Design Patterns") (WEIGHT 4))
;	(course_list (CID SG5225) (NAME "Architecting Software Solutions") (WEIGHT 3))
;	(course_list (CID SG5229) (NAME "Software Maintenance & Evolution") (WEIGHT 2))
;	(course_list (CID SG5230) (NAME "Software Prototyping") (WEIGHT 1))
;)

; Below is the look up (reference) table of 8 sessions with available courses (CID)
(deffacts sessions
	(session S1 SG5230 SG4210 SG5205 SG4202 KE5204 SG5219 SG4205)
	(session S2 SG5222 SG5226 SG4211 KE4202 SG5220 SG5214 SG5227)
	(session S3 SG5208 KE5205 SG5228 KE4204 SG5221 SG5225 SG5231)
	(session S4 SG5209 SG5211 SG4206 SG3204 SG5207 KE4205 SG5229)

	(session S5 SG5230 SG4210 SG5205 SG4202 KE5204 SG5219 SG4205)
	(session S6 SG5222 SG5226 SG4211 KE4202 SG5220 SG5214 SG5227)
	(session S7 SG5208 KE5205 SG5228 KE4204 SG5221 SG5225 SG5231)
	(session S8 SG5209 SG5211 SG4206 SG3204 SG5207 KE4205 SG5229)
)

; Below session_list is to be defined as goal, having 8 session to be filled with course CID.
(deffacts session_list
	(session_list (SID S1))
	(session_list (SID S2))
	(session_list (SID S3))
	(session_list (SID S4))
	(session_list (SID S5))
	(session_list (SID S6))
	(session_list (SID S7))
	(session_list (SID S8))
)


; some global variables used to control matching: weighting value from 28 to 1
(defglobal
	?*counter-weight* = 0
)




; Blew is the sort/integration for part 1 and part 2 function
; 
(defrule give_default_weight
 (declare (salience -200))
	(currentGoal (goal ?NAME) (cf ?CF))
=> 
	(assert (sort_course_list (NAME ?NAME) (CF ?CF) (WEIGHT (+ 1 ?*counter-weight*)) )
	)
	(bind ?*counter-weight* (+ 1 ?*counter-weight*))
)

(defrule sort_course_list
 (declare (salience -210))
	?f <- (sort_course_list (CID ?CID1) (NAME ?NAME1) (CF ?CF1) (WEIGHT ?WEIGHT1) (SID ?SID1))
	?g <- (sort_course_list (CID ?CID2) (NAME ?NAME2) (CF ?CF2) (WEIGHT ?WEIGHT2) (SID ?SID2))
		(test (> ?CF1 ?CF2))
    		(test (= (+ ?WEIGHT1 1) ?WEIGHT2))
=>
    	(retract ?f ?g)
	(assert (sort_course_list (CID ?CID1) (NAME ?NAME1) (CF ?CF1) (WEIGHT ?WEIGHT2) (SID ?SID1))
        	(sort_course_list (CID ?CID2) (NAME ?NAME2) (CF ?CF2) (WEIGHT ?WEIGHT1) (SID ?SID2))
	)
)


(defrule format_course_list ; To populate CID
 (declare (salience -220))
	(currentElective (code ?CID) (elective ?NAME))
	(sort_course_list (CID EMPTY) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
=> 
	(assert (course_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID) )
	)
)



; Blew is the 1st part of part 2 function: To find available sessions for each Course (CID)
; Update course_list with available sessions (SID)
(defrule get-session
 (declare (salience -400))
	(session ?SID $?first ?CID $?last)
	(course_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID1&:(neq ?SID1 ?SID))
	)
=> 
	(assert (course_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID) )
	)
;	?f1 <- (course_list ?CID ?NAME ?CF ?WEIGHT ?SID1)
;	(retract ?f1)
;	(printout t "course id is " ?cid crlf)
;	(printout t ?SID crlf) 
)

; Blew is the 2nd part of part 2 function: To match and fill in unique Course (CID) into each sessions
; from high weighting value to low weighting value
; Update session_list with unique course (CID)
;
;=====================================================================
; 2013 Feb 17
; Sam:
; Below method is very foolish, as I couldn't find a way to do loop...
; Pls see if there is more efficient way.
;=====================================================================
;
;
(defrule match28
 (declare (salience -501))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
;	?f2 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT ?*counter-weight*)) (SID ?SID1&:(eq ?SID1 ?SID)))
	?f28 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 28)) (SID ?SID1&:(eq ?SID1 ?SID)))
;	(test (neq ?f1 ?f2)) ; test pointers and not value
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
;	(retract $?f2)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
;	(bind ?*counter-weight* (- ?*counter-weight* 1))
)
(defrule match27
 (declare (salience -502))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f27 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 27)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match26
 (declare (salience -503))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f26 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 26)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match25
 (declare (salience -504))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f25 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 25)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match24
 (declare (salience -505))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f24 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 24)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match23
 (declare (salience -506))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f23 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 23)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match22
 (declare (salience -507))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f22 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 22)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match21
 (declare (salience -508))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f21 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 21)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match20
 (declare (salience -509))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f20 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 20)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match19
 (declare (salience -510))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f19 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 19)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match18
 (declare (salience -511))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f18 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 18)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match17
 (declare (salience -512))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f17 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 17)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match16
 (declare (salience -513))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f16 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 16)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match15
 (declare (salience -514))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f15 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 15)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match14
 (declare (salience -515))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f14 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 14)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match13
 (declare (salience -516))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f13 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 13)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match12
 (declare (salience -517))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f12 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 12)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match11
 (declare (salience -518))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f11 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 11)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match10
 (declare (salience -519))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f10 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 10)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match9
 (declare (salience -520))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f9 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 9)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match8
 (declare (salience -521))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f8 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 8)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match7
 (declare (salience -522))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f7 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 7)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match6
 (declare (salience -523))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f6 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 6)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match5
 (declare (salience -524))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f5 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 5)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match4
 (declare (salience -525))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f4 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 4)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match3
 (declare (salience -526))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f3 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 3)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match2
 (declare (salience -527))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f2 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 2)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)
(defrule match1
 (declare (salience -528))
	?f0 <- (session_list (CID EMPTY) (SID ?SID))
	?f1 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT&:(= ?WEIGHT 1)) (SID ?SID1&:(eq ?SID1 ?SID)))
=>
;	(printout t crlf "course selected&retracted: " ?CID ?NAME ?WEIGHT ?SID crlf)
	(modify ?f0 (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID)
	)
)


; Blew is rule for house keeping: when a course is filled in a session, ALL course_list facts with this couse should be removed/retracted to avoid double matching.
; put salience 

(defrule housekeep
 (declare (salience -300))
	?f1 <- (session_list (CID ?CID))
	?f2 <- (course_list  (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID))
	(test (neq ?f1 ?f2)) ; test pointers and not value
=>
;	(printout t crlf "course retracted         : " ?CID ?NAME ?WEIGHT ?SID crlf)
	(retract $?f2)
)



; Blew is the 3rd part of part 2 function: To print result
; 
;(defrule display_result
; (declare (salience -100))
;	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID ?SID))
;=>
;	(printout t crlf "| Session: " ?SID " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " " crlf)
;)

(defrule display_result1
 (declare (salience -701))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S1))
=>
	(printout t crlf "| ---------------------------------------------------------------------------")
	(printout t crlf "| Session: " S1 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result2
 (declare (salience -702))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S2))
=>
	(printout t crlf "| Session: " S2 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result3
 (declare (salience -703))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S3))
=>
	(printout t crlf "| Session: " S3 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result4
 (declare (salience -704))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S4))
=>
	(printout t crlf "| Session: " S4 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result5
 (declare (salience -705))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S5))
=>
	(printout t crlf "| Session: " S5 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result6
 (declare (salience -706))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S6))
=>
	(printout t crlf "| Session: " S6 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result7
 (declare (salience -707))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S7))
=>
	(printout t crlf "| Session: " S7 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
)

(defrule display_result8
 (declare (salience -708))
	(session_list (CID ?CID) (NAME ?NAME) (CF ?CF) (WEIGHT ?WEIGHT) (SID S8))
=>
	(printout t crlf "| Session: " S8 " - " ?CID " - " ?NAME " - " ?WEIGHT " - " ?CF " ")
	(printout t crlf "| ---------------------------------------------------------------------------" crlf)
)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Function Definitions

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;(deffunction sort_two_electives (?n1 ?v1 ?n2 ?v2)
;    (if (?v1 < $v2) then
;;        (create$ ?n1 ?v1 ?n2 ?v2) else 
;        (create$ ?n2 ?v2 ?n1 ?v1)
;    )
;)
(defmodule COURSES (import MAIN ?ALL)			;placement of this code affects assert.
              (export deffunction get-course-list)
              (export deffunction get-course-schedule)
              )


(deffunction COURSES::course-sort (?w1 ?w2)
   (< (fact-slot-value ?w1 cf)
      (fact-slot-value ?w2 cf)))
      
(deffunction COURSES::get-course-list ()
  (bind ?facts (find-all-facts ((?f currentGoal)) (>= ?f:cf -2))
	)
  (sort course-sort ?facts))

(deffunction COURSES::get-course-schedule ()
  (bind ?facts (find-all-facts ((?f session_list)) (>= ?f:CF -2))
	)
)
